| 80386响应 中断/异常 的优先级 |
中断/异常类型 | 优先级 |
| 调试故障 | 最高 | |
| 其它故障 | ↓ | |
| 陷阱指令INT n和INTO | ↓ | |
| 调试陷阱 | ↓ | |
| NMI中断 | ↓ | |
| INTR中断 | 最低 |
|
异 常 一 览 表 |
向量号 | 异常名称 | 异常类型 | 出错代码 | 相关指令 |
| 0 | 除法出错 | 故障 | 无 | DIV,IDIV | |
| 1 | 调试异常 | 故障/陷阱 | 无 | 任何指令 | |
| 3 | 单字节INT3 | 陷阱 | 无 | INT 3 | |
| 4 | 溢出 | 陷阱 | 无 | INTO | |
| 5 | 边界检查 | 故障 | 无 | BOUNT | |
| 6 | 非法操作码 | 故障 | 无 | 非法指令编码或操作数 | |
| 7 | 设备不可用 | 故障 | 无 | 浮点指令或WAIT | |
| 8 | 双重故障 | 中止 | 有 | 任何指令 | |
| 9 | 协处理器段越界 | 中止 | 无 | 访问存储器的浮点指令 | |
| 0AH | 无效TSS异常 | 故障 | 有 | JMP、CALL、IRET或中断 | |
| 0BH | 段不存在 | 故障 | 有 | 装载段寄存器的指令 | |
| 0CH | 堆栈段异常 | 故障 | 有 | 装载SS寄存器的任何指令、对SS寻址的段访问的任何指令 | |
| 0DH | 通用保护异常 | 故障 | 有 | 任何特权指令、任何访问存储器的指令 | |
| 0EH | 页异常 | 故障 | 有 | 任何访问存储器的指令 | |
| 10H | 协处理器出错 | 故障 | 无 | 浮点指令或WAIT | |
| 11H—0FFH | 软中断 | 陷阱 | 无 | INT n |
| 出错代码的格式 | |||
| BIT15—BIT3 | BIT2 | BIT1 | BIT0 |
| 选择子的索引部分 | TI | IDT | EXT |

;名称:ASM6.ASM
;功能:演示中断处理的实现
;编译:TASM ASM6.ASM
;连接:TLINK ASM6.OBJ
;----------------------------------------------------------------------------
INCLUDE 386SCD.INC
;----------------------------------------------------------------------------
;部分常量定义
;----------------------------------------------------------------------------
EOICOM = 20h ;外部中断处理结束命令
ICREGP = 20h ;中断控制寄存器端口地址
IMREGP = 21h ;中断屏蔽寄存器端口地址
;----------------------------------------------------------------------------
GDTSeg SEGMENT PARA USE16 ;全局描述符表数据段(16位)
;----------------------------------------------------------------------------
;全局描述符表GDT
GDT LABEL BYTE
;空描述符
DUMMY Desc <>
;规范段描述符
Normal Desc <0ffffh,,,ATDW,,>
;视频缓冲区段描述符(DPL=3)
VideoBuf Desc <0ffffh,8000h,0bh,ATDW,,>
;----------------------------------------------------------------------------
EFFGDT LABEL BYTE
;临时代码段描述符
TempCode Desc <0ffffh,TempCodeSeg,,ATCE,,>
;演示代码段描述符
DemoCode Desc <DemoCodeLen-1,DemoCodeSeg,,ATCE,,>
;演示数据段描述符
DemoData Desc <DemoDataLen-1,DemoDataSeg,,ATDW,,>
;演示堆栈段描述符
DemoStack Desc <DemoStackLen-1,DemoStackSeg,,ATDWA,,>
;0feh号中断处理程序(显示程序)代码段描述符
EchoCode Desc <EchoCodeLen-1,EchoCodeSeg,,ATCE,,>
;0feh号中断处理程序(显示程序)数据段描述符
EchoData Desc <EchoDataLen-1,EchoDataSeg,,ATDW,,>
;8号中断处理程序代码段描述符
TICode Desc <TICodeLen-1,TICodeSeg,,ATCE,,>
;8号中断处理程序数据段描述符
TIData Desc <TIDataLen-1,TIDataSeg,,ATDW,,>
;其它中断或异常处理程序代码段描述符
Other Desc <OtherCodeLen-1,OtherCodeSeg,,ATCE,,>
;----------------------------------------------------------------------------
GDTLen = $-GDT ;全局描述符表长度
GDNum = ($-EFFGDT)/(SIZE Desc) ;需特殊处理的描述符数
;----------------------------------------------------------------------------
Normal_Sel = Normal-GDT ;规范段描述符选择子
Video_Sel = VideoBuf-GDT ;视频缓冲区段描述符选择子
;----------------------------------------------------------------------------
TempCode_Sel = TempCode-GDT ;临时代码段的选择子
DemoCode_Sel = DemoCode-GDT ;演示代码段的选择子
DemoData_Sel = DemoData-GDT ;演示数据段的选择子
DemoStack_Sel = DemoStack-GDT ;演示堆栈段的选择子
EchoCode_Sel = EchoCode-GDT ;0feh号中断程序代码段选择子
EchoData_Sel = EchoData-GDT ;0feh号中断程序数据段选择子
TICode_Sel = TICode-GDT ;8号中断程序代码段选择子
TIData_Sel = TIData-GDT ;8号中断程序数据段选择子
Other_Sel = Other-GDT ;其它中断或异常代码段选择子
;----------------------------------------------------------------------------
GDTSeg ENDS ;全局描述符表段定义结束
;----------------------------------------------------------------------------
IDTSeg SEGMENT PARA USE16 ;中断描述符表数据段(16位)
;----------------------------------------------------------------------------
IDT LABEL BYTE ;中断描述符表
;0--7的8个陷阱门描述符
REPT 8
Gate <OtherBegin,Other_Sel,,AT386TGate,>
ENDM
;对应8号(时钟)中断处理程序的门描述符
Gate <TIBegin,TICode_Sel,,AT386IGate,>
;从9--0fdh的245个陷阱门描述符
REPT 245
Gate <OtherBegin,Other_Sel,,AT386TGate,>
ENDM
;对应0feh号中断处理程序的陷阱门描述符
Gate <EchoBegin,EchoCode_Sel,,AT386TGate,>
;对应0ffh号中断处理程序的陷阱门描述符
Gate <OtherBegin,Other_Sel,,AT386TGate,>
;----------------------------------------------------------------------------
IDTLen = $-IDT
;----------------------------------------------------------------------------
IDTSeg ENDS ;中断描述符表段定义结束
;----------------------------------------------------------------------------
;其它中断或异常处理程序的代码段
;----------------------------------------------------------------------------
OtherCodeSeg SEGMENT PARA USE16
ASSUME CS:OtherCodeSeg
;----------------------------------------------------------------------------
OtherBegin PROC FAR
mov ax,Video_Sel
mov es,ax
mov ah,17h ;在屏幕左上角显示兰底白字
mov al,'!' ;符号"!"
mov WORD PTR es:[0],ax
jmp $ ;无限循环
OtherBegin ENDP
;----------------------------------------------------------------------------
OtherCodeLen = $
OtherCodeSeg ENDS
;----------------------------------------------------------------------------
;8号中断处理程序的数据段
;----------------------------------------------------------------------------
TIDataSeg SEGMENT PARA USE16
Count DB 0 ;中断发生的计数器
TIDataLen = $
TIDataSeg ENDS
;----------------------------------------------------------------------------
;8号中断处理程序的代码段
;----------------------------------------------------------------------------
TICodeSeg SEGMENT PARA USE16
ASSUME CS:TICodeSeg,DS:TIDataSeg
;----------------------------------------------------------------------------
TIBegin PROC FAR
push eax ;保护现场
push ds
push fs
push gs
mov ax,TIData_Sel ;置中断处理程序数据段
mov ds,ax
mov ax,EchoData_Sel ;置显示过程数据段
mov fs,ax
mov ax,DemoData_Sel ;置演示程序数据段
mov gs,ax
cmp Count,0
jnz TI2 ;计数非0表示未到1秒
mov Count,18 ;每秒约18次
int 0feh ;调用0FEH号中断处理程序显示
cmp BYTE PTR fs:Mess,'0'
jnz TI1
mov BYTE PTR gs:Flag,1 ;显示符号'0'时置标记
TI1: dec BYTE PTR fs:Mess ;调整显示符号
TI2: dec Count ;调整计数
pop gs ;恢复现场
pop fs
pop ds
mov al,EOICOM ;通知中断控制器中断处理结束
out ICREGP,al
pop eax
iretd ;中断返回
TIBegin ENDP
;----------------------------------------------------------------------------
TICodeLen = $
TICodeSeg ENDS
;----------------------------------------------------------------------------
;0FEH号中断处理程序数据段
;----------------------------------------------------------------------------
EchoDataSeg SEGMENT PARA USE16
Mess DB '8',4eh
EchoDataLen = $
EchoDataSeg ENDS
;----------------------------------------------------------------------------
;0FEH号中断处理程序(显示程序)的代码段
;----------------------------------------------------------------------------
EchoCodeSeg SEGMENT PARA USE16
ASSUME CS:EchoCodeSeg,DS:EchoDataSeg
;----------------------------------------------------------------------------
EchoBegin PROC FAR
push ax ;保护现场
push ds
push es
mov ax,EchoData_Sel ;置显示过程数据段
mov ds,ax
mov ax,Video_Sel ;置视频缓冲区数据段
mov es,ax
mov ax,WORD PTR Mess
mov WORD PTR es:[0],ax
pop es
pop ds
pop ax
iretd
EchoBegin ENDP
;----------------------------------------------------------------------------
EchoCodeLen = $
EchoCodeSeg ENDS
;----------------------------------------------------------------------------
;演示任务的堆栈段
;----------------------------------------------------------------------------
DemoStackSeg SEGMENT PARA USE16
DemoStackLen = 1024
DB DemoStackLen DUP(0)
DemoStackSeg ENDS
;----------------------------------------------------------------------------
;演示任务的数据段
;----------------------------------------------------------------------------
DemoDataSeg SEGMENT PARA USE16
Flag DB 0
DemoDataLen = $
DemoDataSeg ENDS
;----------------------------------------------------------------------------
;演示任务的代码段
;----------------------------------------------------------------------------
DemoCodeSeg SEGMENT PARA USE16
ASSUME CS:DemoCodeSeg,DS:DemoDataSeg
;----------------------------------------------------------------------------
DemoBegin PROC FAR
mov ax,DemoStack_Sel ;置堆栈
mov ss,ax
mov sp,DemoStackLen ;置数据段
mov ax,DemoData_Sel
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov al,11111110b ;置中断屏蔽字
out IMREGP,al ;只开发时钟中断
sti ;开中断
DemoConti: cmp BYTE PTR Flag,0 ;判标志
jz DemoConti ;直到不为0
cli ;关中断
;转回临时代码段,准备回实方式
JUMP16 TempCode_Sel,<OFFSET ToDos>
DemoBegin ENDP
;----------------------------------------------------------------------------
DemoCodeLen = $
DemoCodeSeg ENDS
;----------------------------------------------------------------------------
TempCodeSeg SEGMENT PARA USE16 ;临时任务的代码段
ASSUME CS:TempCodeSeg
;----------------------------------------------------------------------------
Virtual PROC FAR
JUMP16 DemoCode_Sel,DemoBegin ;转演示任务
ToDos: mov ax,Normal_Sel ;恢复实方式段描述符高速缓存
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov eax,cr0 ;准备返回实模式
and al,11111110b
mov cr0,eax
JUMP16 <SEG Real>,<OFFSET Real>
Virtual ENDP
;----------------------------------------------------------------------------
TempCodeSeg ENDS
;============================================================================
RDataSeg SEGMENT PARA USE16 ;实方式数据段
VGDTR PDesc <GDTLen-1,> ;GDT伪描述符
VIDTR PDesc <IDTLen-1,> ;IDT伪描述符
NORVIDTR PDesc <3ffh,> ;用于保存原IDTR值
SPVar DW ? ;用于保存实方式下的SP
SSVar DW ? ;用于保存实方式下的SS
IMaskRegV DB ? ;用于保存原中断屏蔽寄存器值
RDataSeg ENDS
;----------------------------------------------------------------------------
RCodeSeg SEGMENT PARA USE16 ;实方式代码段
ASSUME CS:RCodeSeg,DS:RDataSeg
;----------------------------------------------------------------------------
Start PROC
mov ax,RDataSeg
mov ds,ax
cld
call InitGDT ;初始化全局描述符表GDT
call InitIDT ;初始化中断描述符表IDT
mov SSVar,ss ;保存堆栈指针
mov SPVar,sp
sidt QWORD PTR NORVIDTR ;保存IDTR
in al,IMREGP
mov BYTE PTR IMaskRegV,al
lgdt QWORD PTR VGDTR ;装载GDTR
cli ;关中断
lidt QWORD PTR VIDTR ;装载IDTR
mov eax,cr0
or al,1
mov cr0,eax
JUMP16 <TempCode_Sel>,<OFFSET Virtual>
Real: mov ax,RDataSeg
mov ds,ax
lss sp,DWORD PTR SPVar ;又回到实方式
lidt QWORD PTR NORVIDTR
mov al,IMaskRegV
out IMREGP,al
sti
mov ax,4c00h
int 21h
Start ENDP
;----------------------------------------------------------------------------
InitGDT PROC
push ds
mov ax,GDTSeg
mov ds,ax
mov cx,GDNum
mov si,OFFSET EFFGDT
InitG: mov ax,[si].BaseL
movzx eax,ax
shl eax,4
shld edx,eax,16
mov WORD PTR [si].BaseL,ax
mov BYTE PTR [si].BaseM,dl
mov BYTE PTR [si].BaseH,dh
add si,SIZE Desc
loop InitG
pop ds
mov bx,16
mov ax,GDTSeg
mul bx
mov WORD PTR VGDTR.Base,ax
mov WORD PTR VGDTR.Base+2,dx
ret
InitGDT ENDP
;----------------------------------------------------------------------------
InitIDT PROC
mov bx,16
mov ax,IDTSeg
mul bx
mov WORD PTR VIDTR.Base,ax
mov WORD PTR VIDTR.Base+2,dx
ret
InitIDT ENDP
;----------------------------------------------------------------------------
RCodeSeg ENDS
END Start
sidt QWORD PTR NORVIDTR
lidt QWORD PTR VIDTR
lidt QWORD PTR NORVIDTR
;名称:ASM7.ASM
;功能:模拟异常和演示异常处理
;编译:TASM ASM7.ASM
;连接:TLINK ASM7.OBJ
;----------------------------------------------------------------------------
INCLUDE 386SCD.INC
;----------------------------------------------------------------------------
GDTSeg SEGMENT PARA USE16 ;全局描述符表数据段(16位)
;----------------------------------------------------------------------------
;全局描述符表GDT
GDT LABEL BYTE
;空描述符
DUMMY Desc <>
;规范段描述符及选择子
Normal Desc <0ffffh,,,ATDW,,>
Normal_Sel = Normal-GDT
;视频缓冲区段描述符(DPL=3)及选择子
VideoBuf Desc <0ffffh,8000h,0bh,ATDW,,>
VideoBuf_Sel = VideoBuf-GDT
;----------------------------------------------------------------------------
EFFGDT LABEL BYTE
;临时代码段描述符及选择子
TempCode Desc <0ffffh,TempCodeSeg,,ATCE,,>
TempCode_Sel = TempCode-GDT
;演示代码段描述符及选择子
DemoCode Desc <DemoCodeLen-1,DemoCodeSeg,,ATCE,,>
DemoCode_Sel = DemoCode-GDT
;演示任务局部描述符表段描述符及选择子
DemoLDT Desc <DemoLDTLen-1,DemoLDTSeg,,ATLDT,,>
DemoLDT_Sel = DemoLDT-GDT
;演示任务TSS段描述符及选择子
DemoTSS Desc <DemoTSSLen-1,DemoTSSSeg,,AT386TSS,,>
DemoTSS_Sel = DemoTSS-GDT
;缓冲数据段描述符及选择子
XBuffer Desc <BufferLen-1,BufferSeg,,ATDW,,>
XBuffer_Sel = XBuffer-GDT
;读键盘任务局部描述符表段描述符及选择子
GKeyLDT Desc <GKeyLDTLen-1,GKeyLDTSeg,,ATLDT,,>
GKeyLDT_Sel = GKeyLDT-GDT
;读键盘任务TSS段描述符及选择子
GKeyTSS Desc <GKeyTSSLen-1,GKeyTSSSeg,,AT386TSS,,>
GKeyTSS_Sel = GKeyTSS-GDT
;显示陷阱处理程序代码段描述符及选择子
EchoCode Desc <EchoCodeLen-1,EchoCodeSeg,,ATCE,,>
EchoCode_Sel = EchoCode-GDT
;显示出错码过程代码段描述符及选择子
SubCode Desc <SubCodeLen-1,SubCodeSeg,,ATCE,,>
SubCode_Sel = SubCode-GDT
;其它中断或异常处理程序代码段描述符及选择子
Other Desc <OtherCodeLen-1,OtherCodeSeg,,ATCE,,>
Other_Sel = Other-GDT
;----------------------------------------------------------------------------
GDTLen = $-GDT ;全局描述符表长度
GDNum = ($-EFFGDT)/(SIZE Desc) ;需处理基地址的描述符个数
;----------------------------------------------------------------------------
GDTSeg ENDS ;全局描述符表段定义结束
;----------------------------------------------------------------------------
IDTSeg SEGMENT PARA USE16 ;中断描述符表数据段(16位)
;----------------------------------------------------------------------------
IDT LABEL BYTE ;中断描述符表
;0号陷阱门描述符(对应除法出错故障)
Gate <DivBegin,Divide_Sel,,AT386TGate,>
;从1--3的3个陷阱门描述符
REPT 3
Gate <OtherBegin,Other_Sel,,AT386TGate,>
ENDM
;4号陷阱门描述符(对应溢出陷阱)
Gate <OFBegin,OF_Sel,,AT386TGate,>
;从5--0ah的的6个陷阱门描述符
REPT 6
Gate <OtherBegin,Other_Sel,,AT386TGate,>
ENDM
;0bh号陷阱门描述符(对应段不存在故障)
Gate <SNPBegin,SNP_Sel,,AT386TGate,>
;0ch号陷阱门描述符(对应堆栈段故障)
Gate <SSEBegin,SSE_Sel,,AT386TGate,>
;0dh号陷阱门描述符(对应通用保护故障)
Gate <GPBegin,GP_Sel,,AT386TGate,>
;从0eh--0edh的240个陷阱门描述符
REPT 240
Gate <OtherBegin,Other_Sel,,AT386TGate,>
ENDM
;对应0feh号陷阱门描述符(对应显示中断处理程序)
Gate <EchoBegin,EchoCode_Sel,,AT386TGate,>
;0ffh号任务门描述符(对应读键盘中断处理任务)
Gate <,GKeyTSS_Sel,,ATTaskGate,>
;----------------------------------------------------------------------------
IDTLen = $-IDT
;----------------------------------------------------------------------------
IDTSeg ENDS ;中断描述符表段定义结束
;----------------------------------------------------------------------------
;读键盘任务局部描述符表段
;----------------------------------------------------------------------------
GKeyLDTSeg SEGMENT PARA USE16
;----------------------------------------------------------------------------
GLDT LABEL BYTE
;代码段描述符及选择子
GKeyCode Desc <0ffffh,GKeyCodeSeg,,ATCE,,>
GKeyCode_Sel = GKeyCode-GLDT+TIL
;堆栈段描述符及选择子
GKeyStack Desc <GKeyStackLen-1,GKeyStackSeg,,ATDWA,,>
GKeyStack_Sel = GKeyStack-GLDT+TIL
;----------------------------------------------------------------------------
GKeyLDNum = ($-GLDT)/(SIZE Desc) ;需初始化基地址的描述符个数
GKeyLDTLen = $ ;局部描述符表段长度
;----------------------------------------------------------------------------
GKeyLDTSeg ENDS
;----------------------------------------------------------------------------
;读键盘任务TSS段
;----------------------------------------------------------------------------
GKeyTSSSeg SEGMENT PARA USE16
DD 0 ;链接字
DD ? ;0级堆栈指针
DW ?,?
DD ? ;1级堆栈指针
DW ?,?
DD ? ;2级堆栈指针
DW ?,?
DD 0 ;CR3
DW GKeyBegin,0 ;EIP
DD 0 ;EFLAGS
DD 0 ;EAX
DD 0 ;ECX
DD 0 ;EDX
DD 0 ;EBX
DW GKeyStackLen,0 ;ESP
DD 0 ;EBP
DD 0 ;ESI
DD 0 ;EDI
DW Normal_Sel,0 ;ES
DW GKeyCode_Sel,0 ;CS
DW GKeyStack_Sel,0 ;SS
DW Normal_Sel,0 ;DS
DW Normal_Sel,0 ;FS
DW Normal_Sel,0 ;GS
DW GKeyLDT_Sel,0 ;LDTR
DW 0 ;调试陷阱标志
DW $+2 ;指向I/O许可位图的偏移
DB 0ffh ;I/O许可位图结束字节
GKeyTSSLen = $
GKeyTSSSeg ENDS
;----------------------------------------------------------------------------
;读键盘任务堆栈段
;----------------------------------------------------------------------------
GKeyStackSeg SEGMENT PARA USE16
GKeyStackLen = 1024
DB GKeyStackLen DUP(0)
GKeyStackSeg ENDS
;----------------------------------------------------------------------------
;读键盘任务代码段
;----------------------------------------------------------------------------
GKeyCodeSeg SEGMENT PARA USE16
ASSUME CS:GKeyCodeSeg,DS:RDataSeg,ES:BufferSeg
;----------------------------------------------------------------------------
GKeyBegin PROC FAR
push ds
push es
push fs
push gs
mov ax,Normal_Sel
mov ss,ax ;准备转实方式
mov eax,cr0
and al,11111110b
mov cr0,eax ;转实方式
JUMP16 <SEG GetKey>,<OFFSET GetKey>
GetKey: mov ax,RDataSeg ;实方式
mov ds,ax
mov ebp,esp ;恢复实方式部分现场
lss sp,DWORD PTR SPVar
lidt QWORD PTR NORVIDTR
sti
mov dx,OFFSET Mess
mov ah,9
int 21h ;显示提示信息
GetKey1: mov ah,0
int 16h ;读键盘
cmp al,'0'
jz GetKey2
cmp al,'4'
jz GetKey2
and al,11011111b ;小写转大写
cmp al,'B'
jb GetKey1
cmp al,'D'
ja GetKey1 ;只有[0,4,b,c,d]有效
GetKey2: mov dl,al
mov ah,2
int 21h ;显示所按字符
mov ax,BufferSeg
mov es,ax
mov BYTE PTR es:KeyASCII,dl ;保存到缓冲数据段
cli ;准备返回保护方式
lidt QWORD PTR VIDTR
mov eax,cr0
or al,1
mov cr0,eax
JUMP16 <GKeyCode_Sel>,<OFFSET GetKeyV>
GetKeyV: mov ax,GKeyStack_Sel ;又进入保护方式
mov ss,ax
mov esp,ebp
pop gs
pop fs
pop es
pop ds
iretd
jmp GKeyBegin
GKeyBegin ENDP
;----------------------------------------------------------------------------
GKeyCodeLen = $
GKeyCodeSeg ENDS
;----------------------------------------------------------------------------
;其它中断或异常处理程序的代码段
;----------------------------------------------------------------------------
OtherCodeSeg SEGMENT PARA USE16
ASSUME CS:OtherCodeSeg
;----------------------------------------------------------------------------
OtherBegin PROC FAR
mov si,OFFSET MessOther
int 0feh ;显示提示信息
mov WORD PTR es:[0],ax
jmp $ ;进入无限循环
OtherBegin ENDP
;----------------------------------------------------------------------------
OtherCodeLen = $
OtherCodeSeg ENDS
;----------------------------------------------------------------------------
;除法出错故障处理程序代码段
;----------------------------------------------------------------------------
DivCodeSeg SEGMENT PARA USE16
ASSUME CS:DivCodeSeg
;----------------------------------------------------------------------------
DivBegin PROC FAR
mov si,OFFSET Mess0
mov di,0
int 0feh ;显示提示信息
shr ax,1 ;处理模拟的除法错误
iretd ;返回
DivBegin ENDP
;----------------------------------------------------------------------------
DivCodeLen = $
DivCodeSeg ENDS
;----------------------------------------------------------------------------
;溢出陷阱处理程序代码段
;----------------------------------------------------------------------------
OFCodeSeg SEGMENT PARA USE16
ASSUME CS:OFCodeSeg
;----------------------------------------------------------------------------
OFBegin PROC FAR
mov si,OFFSET Mess4
mov di,0
int 0feh ;显示提示信息
iretd ;返回
OFBegin ENDP
;----------------------------------------------------------------------------
OFCodeLen = $
OFCodeSeg ENDS
;----------------------------------------------------------------------------
;段不存在故障处理程序代码段
;----------------------------------------------------------------------------
SNPCodeSeg SEGMENT PARA USE16
ASSUME CS:SNPCodeSeg
;----------------------------------------------------------------------------
SNPBegin PROC FAR
mov si,OFFSET MessB
mov di,0
int 0feh ;显示提示信息
pop eax ;弹出出错代码
CALL16 SubCode_Sel,SubBegin ;显示出错代码
pop eax
add eax,2 ;按模拟的引起段不存在指令
push eax ;调整返回地址
iretd
SNPBegin ENDP
;----------------------------------------------------------------------------
SNPCodeLen = $
SNPCodeSeg ENDS
;----------------------------------------------------------------------------
;堆栈段故障处理程序代码段
;----------------------------------------------------------------------------
SSECodeSeg SEGMENT PARA USE16
ASSUME CS:SSECodeSeg
;----------------------------------------------------------------------------
SSEBegin PROC FAR
mov si,OFFSET MessC
mov di,0
int 0feh ;显示提示信息
pop eax ;弹出出错代码
CALL16 SubCode_Sel,SubBegin ;显示出错代码
pop eax
add eax,4 ;按模拟的引起堆栈段错误的
push eax ;指令调整返回地址
iretd
SSEBegin ENDP
;----------------------------------------------------------------------------
SSECodeLen = $
SSECodeSeg ENDS
;----------------------------------------------------------------------------
;通用保护故障处理程序代码段
;----------------------------------------------------------------------------
GPCodeSeg SEGMENT PARA USE16
ASSUME CS:GPCodeSeg
;----------------------------------------------------------------------------
GPBegin PROC FAR
push ebp
mov ebp,esp
push eax
push esi
push edi ;保护现场
mov si,OFFSET MessD
mov di,0
int 0feh ;显示提示信息
mov eax,[bp+4] ;从堆栈中取出出错代码
CALL16 SubCode_Sel,SubBegin ;显示出错代码
pop edi
pop esi
pop eax ;恢复部分现场
add DWORD PTR [ebp+8],2 ;按模拟的故障指令调整返回
pop ebp ;地址
add esp,4 ;废除堆栈中的出错代码
iretd
GPBegin ENDP
;----------------------------------------------------------------------------
;显示出错码过程代码段
;----------------------------------------------------------------------------
SubCodeSeg SEGMENT PARA USE16
ASSUME CS:SubCodeSeG
;----------------------------------------------------------------------------
SubBegin PROC ;AX中含出错代码
push ax ;保护现场
push cx
push dx
push si
push di
mov si,OFFSET ErrCode
mov dx,ax
mov cx,4
SubR1: rol dx,4 ;把16位出错代码转换成4位
mov al,dl ;十六进制数的ASCII码并保存
and al,0fh
add al,30h
cmp al,'9'
jbe SubR2
add al,7
SubR2: mov [si],al
inc si
loop SubR1
mov si,OFFSET ErrMess
Mov di,80*2 ;从第二行行首开始
int 0feh ;显示出错码
pop di ;恢复现场
pop si
pop dx
pop cx
pop ax
retf ;返回
SubBegin ENDP
;----------------------------------------------------------------------------
SubCodeLen = $
SubCodeSeg ENDS
;----------------------------------------------------------------------------
GPCodeLen = $
GPCodeSeg ENDS
;----------------------------------------------------------------------------
;实现显示的陷阱处理程序代码段
;入口参数--DS:SI指向显示信息串,ES:DI指向显示缓冲区
;----------------------------------------------------------------------------
EchoCodeSeg SEGMENT PARA USE16
ASSUME CS:EchoCodeSeg
;----------------------------------------------------------------------------
EchoBegin PROC FAR
pushad ;保护现场
cld
mov ah,7
mov al,20h
mov cx,80
push di
rep stosw ;清所在显示行
pop di
Echo1: lodsb
or al,al
jz Echo2
stosw ;显示指定信息串
jmp Echo1
Echo2: popad ;恢复现场
iretd
EchoBegin ENDP
;----------------------------------------------------------------------------
EchoCodeLen = $
EchoCodeSeg ENDS
;----------------------------------------------------------------------------
;缓冲区数据段
;----------------------------------------------------------------------------
BufferSeg SEGMENT PARA USE16
KeyASCII DB ?
Buffer DB 128 DUP(?)
BufferLen = $
BufferSeg ENDS
;----------------------------------------------------------------------------
;演示任务局部描述符表段
;----------------------------------------------------------------------------
DemoLDTSeg SEGMENT PARA USE16
;----------------------------------------------------------------------------
DLDT LABEL BYTE
;演示任务TSS段作为数据段的描述符及选择子
ToDemoTSS Desc <DemoTSSLen-1,DemoTSSSeg,,ATDW,,>
ToDemoTSS_Sel = ToDemoTSS-DLDT+TIL
;演示任务堆栈段描述符及选择子
DemoStack Desc <DemoStackLen-1,DemoStackSeg,,ATDWA,,>
DemoStack_Sel = DemoStack-DLDT+TIL
;演示任务数据段描述符及选择子
DemoData Desc <DemoDataLen-1,DemoDataSeg,,ATDW,,>
DemoData_Sel = DemoData-DLDT+TIL
;除法出错故障处理程序代码段描述符及选择子
Divide Desc <DivCodeLen-1,DivCodeSeg,,ATCE,,>
Divide_Sel = Divide-DLDT+TIL
;溢出陷阱处理程序代码段描述符及选择子
OverFlow Desc <OFCodeLen-1,OFCodeSeg,,ATCE,,>
OF_Sel = OverFlow-DLDT+TIL
;段不存在故障处理程序代码段描述符及选择子
SNPCode Desc <SNPCodeLen-1,SNPCodeSeg,,ATCE,,>
SNP_Sel = SNPCode-DLDT+TIL
;堆栈段出错故障处理程序代码段描述符及选择子
SSECode Desc <SSECodeLen-1,SSECodeSeg,,ATCE,,>
SSE_Sel = SSECode-DLDT+TIL
;通用保护故障处理程序代码段描述符及选择子
GPCode Desc <GPCodeLen-1,GPCodeSeg,,ATCE,,>
GP_Sel = GPCode-DLDT+TIL
;为模拟段不存在故障而安排的数据段描述符及选择子
TestNPS Desc <0ffffh,,,ATDW-80h,,>
TestNPS_Sel = TestNPS-DLDT+TIL
;----------------------------------------------------------------------------
DemoLDNum = ($-DLDT)/(SIZE Desc) ;LDT描述符个数
DemoLDTLen =$
;----------------------------------------------------------------------------
DemoLDTSeg ENDS
;----------------------------------------------------------------------------
;演示任务TSS段
;----------------------------------------------------------------------------
DemoTSSSeg SEGMENT PARA USE16
DemoTaskSS TSS <>
DB 0ffh
DemoTSSLen = $
DemoTSSSeg ENDS
;----------------------------------------------------------------------------
;演示任务的堆栈段
;----------------------------------------------------------------------------
DemoStackSeg SEGMENT PARA USE16
DemoStackLen = 1024
DB DemoStackLen DUP(0)
DemoStackSeg ENDS
;----------------------------------------------------------------------------
;演示任务的数据段
;----------------------------------------------------------------------------
DemoDataSeg SEGMENT PARA USE16
Mess0 DB 'Divide Error (Exception 0)',0
Mess4 DB 'Overflow (Exception 4)',0
MessB DB 'Segment Not Present (Exception 11)',0
MessC DB 'Stack Segment (Exception 12)',0
MessD DB 'General Protection (Exception 13)',0
MessOther DB 'Other Exception',0
ErrMess DB 'Error Code = '
ErrCode DB 4 DUP(0),'H',0
DemoDataLen = $
DemoDataSeg ENDS
;----------------------------------------------------------------------------
;演示任务的代码段
;----------------------------------------------------------------------------
DemoCodeSeg SEGMENT PARA USE16
ASSUME CS:DemoCodeSeg,DS:DemoDataSeg
;----------------------------------------------------------------------------
DemoBegin PROC FAR
mov ax,DemoLDT_Sel
lldt ax ;装载LDTR
mov ax,DemoStack_Sel ;置堆栈
mov ss,ax
mov esp,DemoStackLen
mov ax,ToDemoTSS_Sel
mov gs,ax ;把演示任务LDT选择子填入TSS
mov WORD PTR gs:DemoTaskSS.TRLDTR,DemoLDT_Sel
mov ax,DemoTSS_Sel
ltr ax ;装载TR
mov ax,DemoData_Sel
mov ds,ax ;装载其它数据段寄存器
mov ax,VideoBuf_Sel
mov es,ax
mov ax,XBuffer_Sel
mov fs,ax
mov ax,XBuffer_Sel
mov gs,ax
int 0ffh ;接收要模拟的异常类型号
mov al,BYTE PTR fs:KeyASCII ;按接收的字符模拟异常号
cmp al,'0'
jnz Demo4
mov ax,2000
mov cl,2 ;模拟除法出错故障
div cl ;该指令长2字节
jmp Over
Demo4: cmp al,'4'
jnz Demo11
mov al,100
add al,50
into ;模拟溢出陷阱
JMP OVER
Demo11: cmp al,'B'
jnz Demo12
mov ax,TestNPS_Sel ;模拟段不存在故障
mov gs,ax ;该指令长2字节
JMP Over
Demo12: cmp al,'C'
jnz Demo13
mov ebp,esp ;模拟堆栈出错故障
mov al,[ebp] ;该指令长4字节
jmp Over
Demo13: mov ax,DemoTSS_Sel ;模拟通用保护故障
mov gs,ax ;该指令长2字节
Over: ;转临时代码段
JUMP16 TempCode_Sel,<OFFSET ToDos>
DemoBegin ENDP
;----------------------------------------------------------------------------
DemoCodeLen = $
DemoCodeSeg ENDS
;----------------------------------------------------------------------------
TempCodeSeg SEGMENT PARA USE16 ;临时任务的代码段
ASSUME CS:TempCodeSeg
;----------------------------------------------------------------------------
Virtual PROC FAR
JUMP16 DemoCode_Sel,DemoBegin ;转演示任务
ToDos: mov ax,Normal_Sel ;恢复实方式段描述符高速缓存
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov eax,cr0 ;准备返回实模式
and al,11111110b
mov cr0,eax
JUMP16 <SEG Real>,<OFFSET Real>
Virtual ENDP
;----------------------------------------------------------------------------
TempCodeSeg ENDS
;============================================================================
RDataSeg SEGMENT PARA USE16 ;实方式数据段
VGDTR PDesc <GDTLen-1,> ;GDT伪描述符
VIDTR PDesc <IDTLen-1,> ;IDT伪描述符
NORVIDTR PDesc <3ffh,> ;用于保存原IDTR值
SPVar DW ? ;用于保存实方式下的SP
SSVar DW ? ;用于保存实方式下的SS
Mess DB 'Press a key[0,4,B,C,D]:$';提示信息
RDataSeg ENDS
;----------------------------------------------------------------------------
RCodeSeg SEGMENT PARA USE16 ;实方式代码段
ASSUME CS:RCodeSeg,DS:RDataSeg
;----------------------------------------------------------------------------
Start PROC
mov ax,RDataSeg
mov ds,ax
cld
call InitGDT ;初始化全局描述符表GDT
call InitIDT ;初始化中断描述符表IDT
mov ax,GKeyLDTSeg
mov fs,ax
mov cx,GKeyLDNum
mov si,OFFSET GLDT
CALL InitLDT
mov ax,DemoLDTSeg
mov fs,ax
mov cx,DemoLDNum
mov si,OFFSET DLDT
CALL InitLDT
mov SSVar,ss ;保存堆栈指针
mov SPVar,sp
lgdt QWORD PTR VGDTR ;装载GDTR
sidt QWORD PTR NORVIDTR ;保存IDTR
cli ;关中断
lidt QWORD PTR VIDTR ;装载IDTR
mov eax,cr0
or al,1
mov cr0,eax
JUMP16 <TempCode_Sel>,<OFFSET Virtual>
Real: mov ax,RDataSeg
mov ds,ax
lss sp,DWORD PTR SPVar ;又回到实方式
lidt QWORD PTR NORVIDTR
sti
mov ax,4c00h
int 21h
Start ENDP
;----------------------------------------------------------------------------
InitGDT PROC
push ds
mov ax,GDTSeg
mov ds,ax
mov cx,GDNum
mov si,OFFSET EFFGDT
InitG: mov ax,[si].BaseL
movzx eax,ax
shl eax,4
shld edx,eax,16
mov WORD PTR [si].BaseL,ax
mov BYTE PTR [si].BaseM,dl
mov BYTE PTR [si].BaseH,dh
add si,SIZE Desc
loop InitG
pop ds
mov bx,16
mov ax,GDTSeg
mul bx
mov WORD PTR VGDTR.Base,ax
mov WORD PTR VGDTR.Base+2,dx
ret
InitGDT ENDP
;----------------------------------------------------------------------------
InitIDT PROC
mov bx,16
mov ax,IDTSeg
mul bx
mov WORD PTR VIDTR.Base,ax
mov WORD PTR VIDTR.Base+2,dx
ret
InitIDT ENDP
;----------------------------------------------------------------------------
;入口参数:FS:SI=第一个要初始化的描述符,CX=要初始化的描述符数
;----------------------------------------------------------------------------
InitLDT PROC
ILDT: mov ax,WORD PTR FS:[si].BaseL
movzx eax,ax
shl eax,4
shld edx,eax,16
mov WORD PTR fs:[si].BaseL,ax
mov BYTE PTR fs:[si].BaseM,dl
mov BYTE PTR fs:[si].BaseH,dh
add si,SIZE Desc
loop ILDT
ret
InitLDT ENDP
;----------------------------------------------------------------------------
RCodeSeg ENDS
END Start



| 参考资料 | 书 名 | 出 版 社 | 作 者 |
| 《保护方式下的80386及其编程》 | 清华大学出版社 | 周明德主编 | |
| 《80X86汇编语言程序设计教程》 | 清华大学出版社 | 扬季文主编 | |
| 《32位系统软件编程指南》 | 电子工业出版社 | 程荷、武航翻译 |